home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Trading on the Edge
/
Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin
/
pc
/
mac_file
/
vendor_d
/
ga_softw
/
ooga
/
pop-meth.lis
< prev
next >
Wrap
Lisp/Scheme
|
1991-02-03
|
26KB
|
767 lines
;;; -*- Mode:Lisp; Package:OOGA; Base:10; Syntax:COMMON-LISP -*-
#||
RESTRICTED RIGHTS LEGEND
Use, duplication, or disclosure by the Government is subject to
restrictions as set forth in subdivision (b)(3)(ii) of the Rights in
Technical Data and Computer Software Clause at 52.227-7013 of the DOD
FAR Supplement.
TSP (The Software Partnership)
P.O. Box 991
Melrose, MA 02176
Copyright 1990 by Lawrence Davis and Daniel Cerys, all rights reserved.
||#
(in-package :ooga)
;;; This file contains methods related to the population module.
;;; **********************************************************************
;;; Variables used to control population member recycling...
;;;
(defvar *OLD-MEMBERS* nil "List of members to recycle")
(defvar *RECYCLE-MEMBERS-FLAG* t "Whether to recycle")
(defvar *RECYCLE-TALLY* 0 "Number of objects recycled since last reset")
;************************************************************
; POPULATION MEMBER
;;; Evaluation-better-p determines whether the GA will be
;;; maximizing or minimizing the evaluation function. The
;;; default is maximizing. This method should be defined for
;;; the population member class of the user's GA is minimization
;;; is required. (See the how-to-examples file for examples of
;;; such definition.)
(defgeneric EVALUATION-BETTER-P (member1 member2)
#-:pcl
(:documentation "Compares the two population members and returns non-NIL if member1's
evaluation is greater than member2's."))
(defmethod EVALUATION-BETTER-P ((member1 t) (member2 t)) t)
(defmethod EVALUATION-BETTER-P ((member1 population-member)
(member2 population-member))
"Default behavior is to treat greater evaluation values as better."
(> (evaluation member1) (evaluation member2)))
;************************************************************
; REPRESENTATION TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((technique representation-technique))
t)
;************************************************************
; INITIALIZATION TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((technique initialization-technique))
t)
;;; Make initial population is a major method in GA runs.
;;; It builds up a list of initial population members until the
;;; list equals the population size desired. First, it uses any
;;; seeds given it by other processes or generated by itself.
;;; Then it creates population members to fill out the initial
;;; population list.
;;; This is a technique that users may wish to tailor for their
;;; own use. Note that if the user uses the seeds option, the
;;; user is responsible for resetting the seeds slot before new
;;; runs.
(defmethod MAKE-INITIAL-POPULATION
((initialization-technique initialization-technique))
"Create the initial population from seeds and new members."
(setf (initial-population initialization-technique)
(loop for seed in (seeds initialization-technique)
collect (seed-population-member initialization-technique seed)))
(create-initial-population initialization-technique))
(defmethod SEED-POPULATION-MEMBER
((initialization-technique initialization-technique) seed)
"Return a population member with the seed as its chromosome."
(let ((new-member
(create-population-member
initialization-technique
(representation-technique
(population-module
initialization-technique)))))
(setf (chromosome new-member) seed)
new-member))
(defmethod CREATE-INITIAL-POPULATION
((initialization-technique initialization-technique))
"Fill the initial population slot with a list of population
members as long as the population size."
(setf (initial-population initialization-technique)
(firstn
(population-size
(population-module initialization-technique))
(append (initial-population initialization-technique)
(loop for n from (1+ (length (initial-population
initialization-technique)))
to (population-size
(population-module
initialization-technique))
with representation-technique =
(representation-technique
(population-module
initialization-technique))
collect (create-population-member
initialization-technique
representation-technique t))))))
;;; This method may generate unneccessary garbage and require
;;; excess overhead. If the user is not maintaining genealogies
;;; or other pointers from parents to children, consider loading
;;; the RECYCLE-POPULATION file to cut down on object creation.
(defun GET-NEW-MEMBER (member-class)
"Return a member of the class. If there is one to recycle, recycle it.
Otherwise, make a new one."
(if *recycle-members-flag*
(let ((old-member (car *old-members*)))
(if (eq (class-name (class-of old-member)) member-class)
(progn (reset old-member)
(setf *old-members* (cdr *old-members*))
(setf *recycle-tally* (1+ *recycle-tally*))
old-member)
(make-instance member-class)))
(make-instance member-class)))
;;; Create a population member. If the initialize? flag is t,
;;; generate a random binary chromosome.
(defmethod CREATE-POPULATION-MEMBER
((initialization-technique random-binary-initialization)
(representation-technique binary-representation)
&optional (initialize? nil))
(let ((new-member (get-new-member
(population-member-class initialization-technique))))
(if initialize? (setf (chromosome new-member)
(create-random-bit-string
(bit-string-length representation-technique))))
new-member))
;;; Create a population member. If the initialize? flag is t,
;;; generate a random real number chromosome.
(defmethod CREATE-POPULATION-MEMBER
((initialization-technique random-real-number-initialization)
(representation-technique real-number-representation)
&optional (initialize? nil))
(let ((new-member (get-new-member
(population-member-class initialization-technique))))
(if initialize? (setf (chromosome new-member)
(create-chromosome representation-technique)))
new-member))
;;; Create a list of real numbers using the real number specs.
(defmethod CREATE-CHROMOSOME
((representation-technique real-number-representation))
(loop repeat (chromosome-length representation-technique)
for specs = (real-number-specs representation-technique)
then (if (cdr specs) (cdr specs) specs)
for spec = (car specs)
collect (make-random-value
(first spec)
(second spec)
(if (third spec) (third spec) nil))))
;;; Create a population member. If the initialize? flag is t,
;;; generate a random permutation chromosome.
(defmethod CREATE-POPULATION-MEMBER
((initialization-technique random-permutation)
(representation-technique permuted-list)
&optional (initialize? nil))
(let ((new-member (get-new-member
(population-member-class initialization-technique))))
(if initialize? (setf (chromosome new-member)
(nscramble (copy-list
(list-to-permute
initialization-technique)))))
new-member))
;;; Note that evaluators for random-permutation initialization
;;; techniques must respond to the LIST-TO-PERMUTE message.
(defmethod INITIALIZE-FOR-RUN ((initialization-technique random-permutation))
"Get the list to permute from the evaluator."
(setf (list-to-permute initialization-technique)
(list-to-permute
(evaluator
(evaluation-module
(ga (population-module initialization-technique)))))))
;************************************************************
; PARENT SELECTION TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((technique parent-selection-technique))
t)
;;; Choose a parent using the roulette wheel method.
(defmethod GET-PARENT ((roulette-wheel roulette-wheel-parent-selection))
"Get a population member by evaluations"
(let ((population-module (population-module roulette-wheel)))
(get-associated-linked-list-element
(first-member population-module)
(fitness-list population-module)
(random (apply '+ (fitness-list population-module)))))) ;; CAN CACHE TOTAL
;************************************************************
; DELETION TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((technique deletion-technique))
t)
;************************************************************
; REPRODUCTION TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((technique reproduction-technique))
t)
;;; Reset the duplicate tally. Set the number of allowed
;;; duplicates to equal the number of desired trials.
(defmethod INITIALIZE-FOR-RUN :AFTER
((reproduction-technique steady-state-without-duplicates))
(setf (duplicate-tally reproduction-technique) 0
(maximum-duplicates reproduction-technique)
(desired-trials
(population-module reproduction-technique))))
;************************************************************
; FITNESS TECHNIQUE
(defmethod INITIALIZE-FOR-RUN ((fitness-technique fitness-is-evaluation))
t)
;;; Set the fitness list to equal the list of population member
;;; evaluations.
(defmethod UPDATE-FITNESS-LIST ((fitness-technique fitness-is-evaluation))
(setf (fitness-list (population-module fitness-technique))
(loop for evaluation in
(evaluations (population-module fitness-technique))
collect (max 0 evaluation))))
;;; Set the fitness list to equal a linearly descending list of
;;; values.
(defmethod INITIALIZE-FOR-RUN ((fitness-technique linear-normalization))
(setf (fitness-list (population-module fitness-technique))
(loop repeat (population-size (population-module fitness-technique))
for value = (max (starting-value fitness-technique)
(minimum-value fitness-technique))
then (max (- value (decrement fitness-technique))
(minimum-value fitness-technique))
collect value)))
;;; A linear fitness list doesn't have to be updated when
;;; members are added or deleted.
(defmethod UPDATE-FITNESS-LIST ((fitness-technique linear-normalization))
t)
;************************************************************
; POPULATION PARAMETERIZATION TECHNIQUES
;;; Begin the interpolation.
(defmethod INITIALIZE-FOR-RUN ((technique interpolate-fitness-decrement))
(setf (decrement (fitness-technique (population-module technique)))
(car (interpolation-specs technique))))
;;; Interpolate the fitness decrement parameter periodically.
;;; If parameter is modified, force the recomputation of the
;;; list of fitnesses.
;;; NOTE: THIS TECHNIQUE SHOULD BE USED ONLY WITH THE LINEAR
;;; NORMALIZATION FITNESS TECHNIQUE.
(defmethod MODIFY-PARAMETERS
((technique interpolate-fitness-decrement)
portion-completed size-of-interval)
(if (even-multiple portion-completed (interpolation-interval technique))
(progn
(setf (decrement (fitness-technique (population-module technique)))
(interpolate 0
(car (interpolation-specs technique))
size-of-interval
(cadr (interpolation-specs technique))
portion-completed))
(initialize-for-run
(fitness-technique (population-module technique))))))
;************************************************************
; POPULATION MODULE
;;; Set up pointers and drive initialization.
(defmethod INITIALIZE-FOR-RUN
((population-module basic-population-module))
(setf (population-module (representation-technique population-module))
population-module
(population-module (initialization-technique population-module))
population-module
(population-module (fitness-technique population-module))
population-module
(Population-module (parent-selection-technique population-module))
population-module
(population-module (deletion-technique population-module))
population-module
(population-module (reproduction-technique population-module))
population-module)
(loop for technique in (parameterization-techniques population-module)
do (setf (population-module technique) population-module)
(initialize-for-run technique))
(setf (first-member population-module) nil
(last-member population-module) nil)
(setf (stop-run? population-module) nil)
(initialize-for-run (representation-technique population-module))
(initialize-for-run (initialization-technique population-module))
(initialize-for-run (fitness-technique population-module))
(initialize-for-run (parent-selection-technique population-module))
(initialize-for-run (deletion-technique population-module))
(initialize-for-run (reproduction-technique population-module))
)
;;; POPULATION INITIALIZATION AND MAINTENANCE
;;; Do bookkeeping. Create the initial population. Update the
;;; fitness list.
(defmethod INITIALIZE-POPULATION
((population-module basic-population-module))
(setf (current-index population-module) 0)
(setf (first-member population-module) nil)
(setf (last-member population-module) nil)
(make-initial-population (initialization-technique population-module))
(loop for new-member in (initial-population
(initialization-technique population-module))
do (prepare-and-install-member population-module new-member))
(update-fitness-list (fitness-technique population-module)))
;;; Set the member index and evaluation. Increment the current
;;; index counter. Install the member in the population.
(defmethod PREPARE-AND-INSTALL-MEMBER
((population-module basic-population-module) new-member)
(setf (current-index population-module) (1+ (current-index population-module)))
(setf (index new-member) (current-index population-module))
(setf (evaluation new-member)
(evaluate-member (evaluation-module
(ga population-module)) new-member))
(install-member population-module new-member))
;;; Delete population members to make room for the new members.
;;; Insert the new members in the population. Update the
;;; fitness list.
(defmethod INSERT-POPULATION-MEMBERS
((population-module basic-population-module) new-members)
(delete-population-members
(deletion-technique population-module) new-members)
(loop for member in new-members
do (prepare-and-install-member population-module member))
(update-fitness-list (fitness-technique population-module)))
;;; Nothing special here.
;;; Delete all population members. Recycle all members unless elitism is
;;; being used.
(defmethod DELETE-POPULATION-MEMBERS
((delete-all delete-all) new-members)
(declare (ignore new-members))
(setf *old-members*
;;There is a bit of a kludge here...
(append (if (eq (class-name (class-of
(reproduction-technique
(population-module delete-all))))
'generational-replacement-with-elitism)
(cdr (population (population-module delete-all)))
(population (population-module delete-all)))
*old-members*))
(setf (first-member (population-module delete-all)) nil
(last-member (population-module delete-all)) nil))
;;; Delete the last population members.
(defmethod DELETE-POPULATION-MEMBERS
((delete-last delete-last) new-members)
(if new-members
(loop with population-module = (population-module delete-last)
for n below (length new-members)
for population-member = (last-member population-module)
then (predecessor population-member)
finally (end-at-member population-module population-member))))
(defmethod END-AT-MEMBER ((population-module basic-population-module) member)
"Cut pointers to the population members that are successors to
the given member."
(let ((old-members (loop for old-member = (successor member)
then (successor old-member)
until (null old-member)
collect old-member)))
(setf *old-members*
(append old-members *old-members*)))
(let ((predecessor (predecessor member)))
(if predecessor (setf (successor predecessor) nil
(predecessor member) nil))
(setf (last-member population-module) predecessor)))
(defmethod SPLICE-OUT-MEMBER
((population-module basic-population-module) member)
"Splice the member out of the population"
(if (null member) (format *standard-output* "~%~%NULL MEMBER"))
(let ((predecessor (predecessor member))
(successor (successor member)))
(when predecessor
(setf (successor predecessor) successor))
(when successor
(setf (predecessor successor) predecessor))
(unless predecessor (setf (first-member population-module) successor))
(unless successor (setf (last-member population-module) predecessor))
(setf (population-module member) nil)
(if (null member) nil ;;; Make member recyclable
(setf *old-members* (cons member *old-members*)))
))
(defmethod INSTALL-MEMBER
((population-module basic-population-module) member)
"Splice the member into the population. Check to see whether
parameters should be interpolated."
(splice-in-member population-module member
(first-member-not-better-than population-module member))
(interpolate-parameters population-module))
(defmethod INTERPOLATE-PARAMETERS
((population-module basic-population-module))
"Drive calls to parameterization techniques after population
has been initialized."
(if (>= (current-index population-module)
(population-size population-module))
(progn
(loop for technique in
(append (parameterization-techniques population-module)
(parameterization-techniques
(reproduction-module (ga population-module))))
do (modify-parameters
technique
(- (current-index population-module) ;;;how far in
(population-size population-module))
(- (desired-trials population-module) ;;; size of interval
(population-size population-module)))))))
(defmethod SPLICE-IN-MEMBER
((population-module basic-population-module) member successor)
"Insert the member into its place (before SUCCESSOR).
If it's the first or last pop member,
set the appropriate population module slot.
The first member to be inserted becomes both first and last population member."
(let ((predecessor (if successor (predecessor successor) nil)))
(link population-module
(if successor (predecessor successor)
(last-member population-module))
member
successor)
(if successor
(unless predecessor
(setf (first-member population-module) member))
(progn (setf (last-member population-module) member)
(if (null (first-member population-module))
(setf (first-member population-module) member))))))
(defmethod FIRST-MEMBER-NOT-BETTER-THAN
((population-module basic-population-module) new-member)
"Returns the first individual in the population with an evaluation not better
than NEW-MEMBER.
It will return NIL if MEMBER is worse than all others."
(loop for current-member = (first-member population-module)
then (successor current-member)
until (null current-member)
do (if (not (evaluation-better-p current-member new-member))
(return current-member))
finally (return nil)))
;************************************************************
;;; EVOLVE: IMPORTANT DRIVER FUNCTION
;;; Evolve causes the GA to generate new population members
;;; after the population has been initialized. This function
;;; continues until a stop run test is passed. If information
;;; about the reason for stopping the run has been given, the
;;; method displays it.
(defmethod EVOLVE ((population-module basic-population-module))
(loop until (terminate-run-test population-module)
with reproduction-module = (reproduction-module (ga population-module))
do (let ((new-members (reproduce (reproduction-technique population-module)
reproduction-module)))
(insert-population-members population-module new-members)
(update-fitness-list (fitness-technique population-module)))
finally (if (stop-run? population-module)
(loop for item in (stop-run? population-module)
do (print item)))))
;************************************************************
;;; RETRIEVAL FUNCTIONS AND TESTS
(defmethod GET-PARENT ((population-module basic-population-module))
"Return a parent."
(get-parent (parent-selection-technique population-module)))
(defmethod TERMINATE-RUN-TEST ((population-module basic-population-module))
"The default method is to stop a run when the number of
evaluations equals or exceeds the number of desired trials."
(or (stop-run? population-module)
(>= (current-index population-module)
(desired-trials population-module))))
;;; Since the population isn't a list, this builds and returns
;;; the list.
(defmethod POPULATION ((population-module basic-population-module))
(do ((member (last-member population-module) (predecessor member)) ;We're going backwards...
(list nil))
((null member) list)
(push member list)))
;;; Same for the population in reverse.
(defmethod REVERSE-POPULATION ((population-module basic-population-module))
(do ((member (first-member population-module) (successor member)) ;We're going backwards...
(list nil))
((null member) list)
(push member list)))
;;; Return a list of the population members' evaluations.
(defmethod EVALUATIONS ((population-module basic-population-module))
(map-over-elements 'evaluation population-module))
;************************************************************
; PERIODIC STATE DISPLAY
;;; The periodic state display routine displays the state of the
;;; GA periodically if the display flag is non-null. It also
;;; displays the state after population is initialized and when
;;; the run has been terminated.
(defmethod INITIALIZE-POPULATION :AFTER
((display-state-routine periodic-state-display))
(if (display-flag display-state-routine)
(format *standard-output*
"~%~%AT ~a POPULATION IS INITIALIZED WITH BEST EVALUATION ~a"
(current-index display-state-routine)
(evaluation (first-member display-state-routine)))))
(defmethod INSTALL-MEMBER :AFTER
((display-state-routine periodic-state-display) member)
"Display the current population sorted by evaluation"
(declare (ignore member))
(if (even-multiple (current-index display-state-routine)
(display-period display-state-routine))
(if (display-flag display-state-routine)
(display-state display-state-routine))))
(defmethod TERMINATE-RUN :AFTER ((display-state-routine periodic-state-display))
"Ensure that we display the final state."
(if (not (even-multiple (current-index display-state-routine)
(display-period display-state-routine)))
(if (display-flag display-state-routine)
(display-state display-state-routine))))
(defmethod DISPLAY-STATE ((display-state-routine periodic-state-display))
"This method should be specialized for the application."
(format *standard-output* "~%~%~%AT ~a BEST ~a CHROMOSOMES ARE:~%"
(current-index display-state-routine)
(number-to-display display-state-routine))
(loop for member in (firstn (number-to-display display-state-routine)
(population display-state-routine))
do (if (null member) t
(display-member
(representation-technique display-state-routine) member))))
;************************************************************
; PERIODIC PERFORMANCE STATISTICS COLLECTION
;;; These routines collect statistics periodically. Use the
;;; average-performance method to get an average of the
;;; performance across runs.
(defmethod INITIALIZE-POPULATION :BEFORE
((population-module performance-statistics-collection))
(setf (performance-statistics population-module)
(push '() (performance-statistics population-module))))
(defmethod INSTALL-MEMBER :AFTER
((population-module performance-statistics-collection) member)
(declare (ignore member))
(if (even-multiple (current-index population-module)
(performance-statistics-interval population-module))
(push (list (current-index population-module)
(evaluation (first-member population-module)))
(car (performance-statistics population-module)))))
(defmethod RUN :AFTER ((population-module performance-statistics-collection))
"Ensure that we collect the statistics for the final state."
(if (= (current-index population-module)
(caaar (performance-statistics population-module)))
t
(push (list (current-index population-module)
(evaluation (first-member population-module)))
(car (performance-statistics population-module)))))
(defmethod AVERAGE-PERFORMANCE
((population-module performance-statistics-collection))
(average-cadrs (performance-statistics population-module)))
;************************************************************
; EVALUATION MODULE
;;; The evaluation module returns evaluations. The user should
;;; define the evaluator. (See examples in the HOW-TO-EXAMPLES
;;; file.)
(defmethod EVALUATE-MEMBER ((evaluation-module basic-evaluation-module) member)
(evaluate-member (evaluator evaluation-module) member))
(defmethod INITIALIZE-FOR-RUN ((evaluation-module basic-evaluation-module))
(setf (evaluation-module (evaluator evaluation-module)) evaluation-module))
;;; The following are routines for recycling population members, thereby
;;; cutting down on garbage collection and object creation requirements.
;;; Note that there is potential for errors creeping in if population
;;; member fields are not cleared when they are recycled. The user should
;;; be careful to clear additional fields of user-defined population member
;;; classes with :AFTER RESET methods similar to those below.
;;; NOTE ALSO THAT RECYCLING SHOULD NOT BE USED WITH THE ADAPTIVE
;;; PARAMETERIZATION UTILITIES, NOR WITH ANY SYSTEM REQUIRING GENEALOGY
;;; MAINTENANCE.
;;; To turn off the recycling procedures, set the
;;; *recycle-members-flag* to nil.
(defmethod RESET ((member population-member))
"Clear the member fields."
(setf (evaluation member) nil
(chromosome member) nil
(index member) nil
(population-module member) nil))
(defmethod RESET :AFTER ((member doubly-linked-list-element))
"Chop pointers to predecessor and successor"
(setf (predecessor member) nil
(successor member) nil))